#pragma once

#include <algorithm>
#include <iterator>
#include <vector>
#include <type_traits>
#include <optional>
#include <ostream>
#include <string>

#include "TxDNN/txdnn.h"
#include "utils/string_utils/string_utils.h"

#include "operators/kernel_info.h"
#include "operators/invoker.h"


namespace txdnn {
namespace operators {

/*
 * Operators contains information required to build and run a kernel or a graph of kernels.
 * which is expected to perform computations as per problem config.
 *
 */
struct Operators {
public:
  Operators(txdnnStatus_t status = TXDNN_STATUS_SUCCESS) : status_(status) {}

  inline bool succeeded() const { return status_ == TXDNN_STATUS_SUCCESS; }

public:
  txdnnStatus_t status_;
  std::string op_id_;
  std::vector<KernelInfo> construct_params_; // may consist of multiple kernels
  std::optional<InvokerFactory> invoker_factory_;
};

std::ostream& operator<<(std::ostream& os, const Operators& op) {
  std::vector<std::string> strs;
  std::transform(op.construct_params_.begin(), op.construct_params_.end(), std::back_inserter(strs),
                 [](auto k) { return k.kernel_name; });
  os << op.op_id_ << ": " << JoinStrings(strs, "/");
  return os;
}

} // namespace operators
} // namespace txdnn